from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from pydantic import BaseModel, EmailStr, Field, validator
from typing import Optional, List, Dict, Any
import jwt
from datetime import datetime, timedelta
import database
import os
import re
from fastapi.responses import JSONResponse

# 创建路由
router = APIRouter(tags=["auth"])

# 定义JWT配置
SECRET_KEY = os.environ.get("JWT_SECRET_KEY", "music_ocr_super_secret_key_for_jwt_token_generation")
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 60 * 24 * 30  # 30天

# 定义OAuth2密码授权
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/auth/login", auto_error=False)

# 定义模型
class UserLogin(BaseModel):
    username: str
    password: str
    remember_me: bool = False

class UserRegisterBasic(BaseModel):
    username: str = Field(..., min_length=4, max_length=20)
    email: EmailStr
    password: str = Field(..., min_length=8)
    confirm_password: str
    
    @validator('username')
    def username_alphanumeric(cls, v):
        if not re.match(r'^[a-zA-Z0-9_]+$', v):
            raise ValueError('用户名只能包含字母、数字和下划线')
        return v
        
    @validator('confirm_password')
    def passwords_match(cls, v, values, **kwargs):
        if 'password' in values and v != values['password']:
            raise ValueError('两次输入的密码不匹配')
        return v

class UserRegisterPreferences(BaseModel):
    music_identity: str
    instruments: List[str] = []
    genres: List[str] = []
    reasons: List[str] = []
    playsInstrument: str = "no"
    otherInstrument: Optional[str] = None
    otherReason: Optional[str] = None

class TokenResponse(BaseModel):
    access_token: str
    token_type: str
    user: dict

class UserProfileResponse(BaseModel):
    id: int
    username: str
    email: str
    full_name: Optional[str] = None
    avatar_url: Optional[str] = None
    music_identity: str
    preferences: Dict[str, List[str]] = {}
    stats: Dict[str, int] = {}

# 创建令牌
def create_access_token(data: dict, expires_delta: timedelta = None):
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt

# 解析令牌
def decode_token(token: str):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        return payload
    except jwt.PyJWTError:
        return None

# 格式化用户响应数据
def format_user_response(user):
    stats = {
        "scanned": user.get("scanned_count", 0),
        "conversations": user.get("conversation_count", 0),
        "posts": user.get("post_count", 0),
        "comments": user.get("comment_count", 0)
    }
    
    return {
        "id": user["id"],
        "username": user["username"],
        "email": user["email"],
        "name": user.get("full_name", user["username"]),
        "avatar": user.get("avatar_url"),
        "musicIdentity": user.get("music_identity", "hobbyist"),
        "preferences": user.get("preferences", {}),
        "stats": stats
    }

# 登录路由
@router.post("/login", response_model=TokenResponse)
async def login(user_data: UserLogin):
    # 验证用户
    user = database.get_user_by_username(user_data.username)
    if not user:
        user = database.get_user_by_email(user_data.username)  # 尝试邮箱登录
    
    if not user or not database.verify_password(user_data.password, user["password_hash"]):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="用户名或密码错误",
            headers={"WWW-Authenticate": "Bearer"},
        )
    
    # 获取详细用户信息
    user_details = database.get_user_details(user["id"])
    
    # 创建访问令牌
    token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) if user_data.remember_me else None
    access_token = create_access_token(
        data={"sub": user["username"], "id": user["id"]}, 
        expires_delta=token_expires
    )
    
    # 返回令牌和用户信息
    return {
        "access_token": access_token,
        "token_type": "bearer",
        "user": format_user_response(user_details)
    }

# 注册第一步 - 基本信息
@router.post("/register/basic")
async def register_basic(user_data: UserRegisterBasic):
    # 检查用户名是否已存在
    existing_user = database.get_user_by_username(user_data.username)
    if existing_user:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="用户名已存在"
        )
    
    # 检查邮箱是否已存在
    existing_email = database.get_user_by_email(user_data.email)
    if existing_email:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="邮箱已被注册"
        )
    
    # 临时存储注册信息（实际应用中可以使用Redis或其他方法）
    return {"status": "success", "message": "基本信息验证通过"}

# 注册第二步 - 音乐偏好
@router.post("/register/complete")
async def register_complete(basic_info: UserRegisterBasic, preferences: UserRegisterPreferences):
    try:
        # 创建用户
        user_id = database.create_user(
            username=basic_info.username,
            email=basic_info.email,
            password=basic_info.password,
            music_identity=preferences.music_identity
        )
        
        # 添加用户偏好
        if preferences.instruments:
            database.add_user_preferences(user_id, "instrument", preferences.instruments)
        
        if preferences.genres:
            database.add_user_preferences(user_id, "genre", preferences.genres)
        
        if preferences.reasons:
            database.add_user_preferences(user_id, "reason", preferences.reasons)
        
        # 添加其他自定义输入
        if preferences.playsInstrument == "yes" and preferences.otherInstrument and "other" in preferences.instruments:
            database.add_user_preferences(user_id, "instrument", [preferences.otherInstrument])
        
        if preferences.otherReason and "other" in preferences.reasons:
            database.add_user_preferences(user_id, "reason", [preferences.otherReason])
        
        # 获取用户详细信息
        user_details = database.get_user_details(user_id)
        
        # 创建访问令牌
        access_token = create_access_token(
            data={"sub": basic_info.username, "id": user_id}
        )
        
        # 返回令牌和用户信息
        return {
            "access_token": access_token,
            "token_type": "bearer",
            "user": format_user_response(user_details)
        }
        
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"注册失败: {str(e)}"
        )

# 获取当前用户信息
@router.get("/me", response_model=UserProfileResponse)
async def get_current_user(token: Optional[str] = None, authorization: Optional[str] = Depends(oauth2_scheme)):
    try:
        # 尝试从查询参数获取token
        if not token and authorization:
            # 从Authorization头部获取token，格式为"Bearer {token}"
            if authorization.startswith("Bearer "):
                token = authorization.replace("Bearer ", "")
            else:
                token = authorization  # 兼容不带Bearer前缀的情况
        
        if not token:
            # 使用自定义响应，确保添加CORS头
            response = JSONResponse(
                status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
                content={"detail": "缺少认证令牌"}
            )
            response.headers["Access-Control-Allow-Origin"] = "*"
            response.headers["Access-Control-Allow-Headers"] = "*"
            response.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS"
            return response
        
        payload = decode_token(token)
        if not payload or "id" not in payload:
            # 使用自定义响应，确保添加CORS头
            response = JSONResponse(
                status_code=status.HTTP_401_UNAUTHORIZED,
                content={"detail": "无效的凭证"}
            )
            response.headers["Access-Control-Allow-Origin"] = "*"
            response.headers["Access-Control-Allow-Headers"] = "*"
            response.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS"
            return response
        
        user_id = payload["id"]
        user = database.get_user_details(user_id)
        
        if not user:
            # 使用自定义响应，确保添加CORS头
            response = JSONResponse(
                status_code=status.HTTP_404_NOT_FOUND,
                content={"detail": "用户不存在"}
            )
            response.headers["Access-Control-Allow-Origin"] = "*"
            response.headers["Access-Control-Allow-Headers"] = "*"
            response.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS"
            return response
        
        # 用于API响应的用户数据
        user_data = format_user_response(user)
        
        # 用于依赖注入的User对象
        user_obj = User(
            id=user["id"],
            username=user["username"],
            email=user["email"]
        )
        
        # 根据上下文返回不同的结果
        if authorization:  # 通过依赖注入调用
            return user_obj
        else:  # 直接API调用
            # 使用自定义响应，添加CORS头
            response = JSONResponse(content=user_data)
            response.headers["Access-Control-Allow-Origin"] = "*"
            response.headers["Access-Control-Allow-Headers"] = "*"
            response.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS"
            return response
    except Exception as e:
        # 捕获所有异常并确保返回的错误响应也有CORS头
        response = JSONResponse(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            content={"detail": f"获取用户信息失败: {str(e)}"}
        )
        response.headers["Access-Control-Allow-Origin"] = "*"
        response.headers["Access-Control-Allow-Headers"] = "*"
        response.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS"
        return response

# 添加预检请求处理
@router.options("/me")
async def options_me():
    response = JSONResponse({})
    response.headers["Access-Control-Allow-Origin"] = "*"
    response.headers["Access-Control-Allow-Headers"] = "*"
    response.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS"
    return response

# 定义User类，用于依赖注入
class User(BaseModel):
    id: int
    username: str
    email: str

# 从token获取用户ID
def get_user_id_from_token(token: str) -> int:
    payload = decode_token(token)
    if not payload or "id" not in payload:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="无效的凭证"
        )
    return payload["id"] 